import re
import pandas as pd
from dataclasses import dataclass

@dataclass
class SEItem:
    eid: str
    etype: str
    level: int
    id : int
    start: int
    end : int

TITLE_RE=re.compile(r'(#\+\s+)*a\d+b\d+(\.\d+)*(\w)*')  # a33b4.1.3.5a  ()默认是生效的
NTITLE_REX = re.compile(r'#+\s*(\d+\.*)*\s+')    # 匹配标题 #
SEITEM_REX = re.compile(r'RTS([A-Z]+-)+(\d+)[#\*]*')    # 匹配 BYDSRS-0/BYD-SRS-1
PIC_PREFIX = '![图'

class SEAst:
    def __init__(self, etype:str):
        self.etype = etype
        self.reset()

    def reset(self):
        self.ast = []
        self.lasttype = ""
        self.lastlevel = -1
        self.in_block = 0

    def push(self, line: str, lineno: int):
        """压入一行文本

        Args:
            line (str): 待处理文本
            lineno (int): 行号
        """
        etype, param = self.get_type(line)
        match etype:
            case 'title':
                title = line.lstrip('#').strip()
                level = param
                se = SEItem(title, etype, level, 0, lineno, lineno+1)
                self.lastlevel = level
            case 'block':
                if self.lasttype == 'title':
                    self.lastlevel += 1
                se = SEItem(param[0], etype, self.lastlevel, param[1], lineno, 0)
            case _:
                return
        # 如果上一个元素是block，说明可能没有结束，更新上一个元素的结束位置
        if self.lasttype == 'block':
            if len(self.ast) > 0 and self.ast[-1].end==0:
                self.ast[-1].end = lineno
        self.ast.append(se)
        self.lasttype = etype  

    def parse_file(self, filename):
        with open(filename, 'r', encoding='utf-8') as f:
            lines = f.readlines()
            ast = self.parse_lines(lines)
            df = self.export_ast(lines, ast)
            return ast, df

    def parse_lines(self, lines):
        for i, line in enumerate(lines):
            self.push(line, i)
            # 更新最后一个元素的结束位置
        self.ast[-1].end = len(lines)
        return self.ast

    def get_type(self, line: str):
        """
        @brief 获取类型
        @param line: 输入的文本
        @return 返回类型和参数
            标题类型返回: 
                - 标题内容
                - 标题级别
        """
        if not self.in_block:
            if line.startswith('#'):
                return 'title', line[0:20].count('#')
            elif line.startswith('!['):
                return 'pic', None
            else:
                return self.get_custom_type(line)
        else:
            if self.is_block_end(self.lasttype, line):
                return 'block_end'

    def is_block_end(self, etype:str, line:str):
        match etype:
            case 'swrs':
                pass
            case 'ats_swrs':
                pass

    def get_custom_type(self, line: str):
        """获取自定义的类型

        Args:
            line (str): 文本输入

        Returns:
            返回: 类型+参数
                如果是block, 则参数为:
                    - blockid
                    - blockid结束位置
        """
        mret = SEITEM_REX.search(line)
        if mret:
            return 'block', [mret.group(0), mret.end(0)]
        else:
            return 'other', None
        
    def parse_block(self, module: str, eid:str, lines: str):
        """解析block

        Args:
            text (str): block文本

        Returns:
            返回: 
                - block标题
                - block内容
                - block安全性
        """
        safety = '是' if eid.endswith('*') else '否'
        title = module+'-'+eid.split('-')[-1].rstrip('*#')
        content = '\n'.join(lines)[len(eid):].strip()
        return title, content, safety

    def export_ast(self, lines: list[str], ast: list[SEItem]):
        """导出ast
        """
        # df = pd.DataFrame(columns=['module', 'title', 'content', 'safety'])
        ret = []
        cur_module = ''
        for item in ast:
            if item.etype == 'title':
                cur_module = item.eid.split()[-1]
            elif item.etype == 'block':
                title, content, safety = self.parse_block(cur_module, item.eid, lines[item.start:item.end])
                ret.append({'module': cur_module,  'id': item.eid, 'title': title,
                'content': content, 'safety': safety})
        return pd.DataFrame(ret)

